package com.usb2uartagent;


import android.content.Context;

import com.csjbot.csjbase.log.Csjlogger;

import java.util.Arrays;

import tw.com.prolific.driver.pl2303.PL2303Driver;

/**
 * Copyright (c) 2017, SuZhou CsjBot. All Rights Reserved.
 * www.csjbot.com
 * <p>
 * Created by 浦耀宗 at 2017/02/09 0009-14:06.
 * Email: puyz@csjbot.com
 */

public class Usb2UartagentSingleManager {
    private PL2303Driver.DataBits mDataBits = PL2303Driver.DataBits.D8;
    private PL2303Driver.Parity mParity = PL2303Driver.Parity.NONE;
    private PL2303Driver.StopBits mStopBits = PL2303Driver.StopBits.S1;
    private PL2303Driver.FlowControl mFlowControl = PL2303Driver.FlowControl.OFF;

    private volatile PL2303Driver mPL2303Driver;
    private static final String ACTION_USB_PERMISSION = "com.csjbot.snowbot.USB_PERMISSION";
    private Context mContext;
    private ReadRunnable readRunnable;

    private static Usb2UartagentSingleManager mUsb2UartagentManager = new Usb2UartagentSingleManager();


    private Usb2UartagentSingleManager() {
        readRunnable = new ReadRunnable();

    }

    /**
     * 如果需要对数据进行拼包、拆包的处理，实现此接口
     */
    public interface DataHandler {
        void handleData(byte[] data, int length);
    }

    public int init(Context context, PL2303Driver.BaudRate baudRate) {
        Csjlogger.info("USB init");
        mPL2303Driver = new PL2303Driver((android.hardware.usb.UsbManager) context.getSystemService(Context.USB_SERVICE),
                context, ACTION_USB_PERMISSION);

        if (!mPL2303Driver.PL2303USBFeatureSupported()) {
            mPL2303Driver = null;
            Csjlogger.error("No Support USB host API");
            return Error.Usb.NO_SUPPORT_USB_HOST_API_ERROR;
        }

        if (!mPL2303Driver.isConnected()) {
            Csjlogger.info("New instance : " + mPL2303Driver);
            if (!mPL2303Driver.enumerate()) {
                Csjlogger.error("no more devices found");
                return Error.Usb.NO_MORE_DEVICES_FOUND;
            } else {
                Csjlogger.debug("onResume:enumerate succeeded!");
            }
        }//if isConnected

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return open(baudRate);
    }

    private int open(PL2303Driver.BaudRate baudRate) {
        if (mPL2303Driver.isConnected()) {
            if (!mPL2303Driver.InitByBaudRate(baudRate, 700)) {
                if (!mPL2303Driver.PL2303Device_IsHasPermission()) {
                    Csjlogger.error("cannot open, maybe no permission");
                    return Error.Usb.CANNOT_OPEN_MAYBE_NO_PERMISSION;
                }

                if (mPL2303Driver.PL2303Device_IsHasPermission() && (!mPL2303Driver.PL2303Device_IsSupportChip())) {
                    Csjlogger.error("cannot open, maybe this chip has no support, please use PL2303HXD / RA / EA chip.");
                    return Error.Usb.CANNOT_OPEN_CHIP_NO_SUPPORT;
                }
            }
            new Thread(readRunnable).start();
        } else {
            Csjlogger.error("usb is not connecnted!");
            return Error.Usb.DEVICE_NOT_CONNECTED;
        }
        return Error.Usb.INIT_OK;
    }

    public void setDataHandle(DataHandler dataHandle) {
        readRunnable.setDataHandler(dataHandle);
    }

    public static Usb2UartagentSingleManager getInstance() {
        return mUsb2UartagentManager;
    }

    class ReadRunnable implements Runnable {
        private static final long READ_INTERVAL = 60;
        private byte[] readBuf = new byte[2048];
        private boolean bStop = false;
        private DataHandler dataHandler;
        private int detectType = -1;

        @Override
        public void run() {
            Csjlogger.debug("ReadRunnable start run");

            while (!bStop) {
                int readLen = mPL2303Driver.read(readBuf);
//                Csjlogger.error("ReadRunnable", " usb recv " + readLen + " bytes!");
//                Csjlogger.debug("ReadRunnable " + Arrays.toString(Arrays.copyOf(readBuf, readLen)));
                if (readLen > 0) {
                    if (dataHandler != null) {
                        dataHandler.handleData(Arrays.copyOf(readBuf, readLen), readLen);
                    }
                }
//                else
//                {
//                    Csjlogger.error(TAG, deviceIndex + " usb recv " + readLen + " bytes!");
//                }
                try {
                    Thread.sleep(READ_INTERVAL);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    return;
                }
            }
        }

        public void stopRead() {
            bStop = true;
            Thread.currentThread().interrupt();
        }

        public ReadRunnable() {
        }

        public void setDataHandler(DataHandler dataHandler) {
            this.dataHandler = dataHandler;
        }

        public boolean isbStop() {
            return bStop;
        }

        public void startRead() {
            bStop = false;
            new Thread(this).start();
        }

        public void setDetectType(int detectType) {
            this.detectType = detectType;
        }

        public int getDetectType() {
            return detectType;
        }
    }

    /**
     * 发送数据
     *
     * @param data
     */
    public int sendData(byte[] data) {
        if (null == mPL2303Driver) {
            return Error.Usb.SEND_DEVICE_NULL_ERROR;
        }

        if (!mPL2303Driver.isConnected()) {
            return Error.Usb.SEND_NO_USB_CONNECT_ERROR;
        }

        int res = mPL2303Driver.write(data, data.length);
        if (res < 0) {
            Csjlogger.error("Fail to controlTransfer");
            return res;
        }

        return Error.Usb.SEND_SUCCESS;
    }
}
